package com.foo.demo.dao;

import com.foo.demo.util.PropertiesUtil;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;


public class BaseDao {
    private static Logger logger = LogManager.getLogger();

    private DataSource dataSource;

    private DataSource getDataSource() {

        synchronized (BaseDao.class) {
            if (null == dataSource) {
                String driverClass = PropertiesUtil.getValue("jdbc.properties", "jdbc.driverClass");
                String url = PropertiesUtil.getValue("jdbc.properties", "jdbc.url");
                String username = PropertiesUtil.getValue("jdbc.properties", "jdbc.username");
                String password = PropertiesUtil.getValue("jdbc.properties", "jdbc.password");
                String validateQuery = PropertiesUtil.getValue("jdbc.properties", "jdbc.validateQuery");
                String maxTotal = PropertiesUtil.getValue("jdbc.properties", "jdbc.maxTotal");
                String maxIdle = PropertiesUtil.getValue("jdbc.properties", "jdbc.maxIdle");
                String minIdle = PropertiesUtil.getValue("jdbc.properties", "jdbc.minIdle");
                String maxWait = PropertiesUtil.getValue("jdbc.properties", "jdbc.maxWait");
                String timeBetweenEvictionRunsMillis = PropertiesUtil.getValue("jdbc.properties", "jdbc.timeBetweenEvictionRunsMillis");
                String minEvictableIdleTimeMillis = PropertiesUtil.getValue("jdbc.properties", "jdbc.minEvictableIdleTimeMillis");
                String testWhileIdle = PropertiesUtil.getValue("jdbc.properties", "jdbc.testWhileIdle");
                String testOnBorrow = PropertiesUtil.getValue("jdbc.properties", "jdbc.testOnBorrow");
                String removeAbanadoned = PropertiesUtil.getValue("jdbc.properties", "jdbc.removeAbanadoned");
                String removeAbandonedTimeout = PropertiesUtil.getValue("jdbc.properties", "jdbc.removeAbandonedTimeout");
                String logAbandonded = PropertiesUtil.getValue("jdbc.properties", "jdbc.logAbandonded");


                boolean b = DbUtils.loadDriver(driverClass);
                if (!b) {
                    throw new RuntimeException("加载数据库驱动失败");
                }

                try {
                    DriverManagerConnectionFactory driverManagerConnectionFactory = new DriverManagerConnectionFactory(url, username, password);
                    PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(driverManagerConnectionFactory, null);
                    poolableConnectionFactory.setValidationQuery(validateQuery);
                    logger.info("Creating pool " + url);
                    GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<PoolableConnection>(poolableConnectionFactory);
                    pool.setMaxTotal(Integer.parseInt(maxTotal));
                    pool.setMaxIdle(Integer.parseInt(maxIdle));
                    pool.setMinIdle(Integer.parseInt(minIdle));
                    pool.setMaxWaitMillis(Long.parseLong(maxWait));
                    pool.setTimeBetweenEvictionRunsMillis(Long.parseLong(timeBetweenEvictionRunsMillis));
                    pool.setMinEvictableIdleTimeMillis(Long.parseLong(minEvictableIdleTimeMillis));
                    pool.setTestWhileIdle(Boolean.parseBoolean(testWhileIdle));
                    pool.setTestOnBorrow(Boolean.parseBoolean(testOnBorrow));

                    AbandonedConfig abandonedConfig = new AbandonedConfig();
                    abandonedConfig.setRemoveAbandonedOnMaintenance(Boolean.parseBoolean(removeAbanadoned));
                    abandonedConfig.setRemoveAbandonedTimeout(Integer.parseInt(removeAbandonedTimeout));
                    abandonedConfig.setLogAbandoned(Boolean.parseBoolean(logAbandonded));

                    pool.setAbandonedConfig(abandonedConfig);

                    poolableConnectionFactory.setPool(pool);
                    dataSource = new PoolingDataSource<>(pool);
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error("链接数据库错误");
                }
            }
        }

        return dataSource;
    }

    public int insert(String sql, Object[] objectArr) {
        QueryRunner queryRunner = new QueryRunner(getDataSource());
        ArrayHandler arrayHandler = new ArrayHandler();

        try {
            Object[] insert = queryRunner.insert(sql, arrayHandler, objectArr);
            return 1;
        } catch (SQLException e) {
            logger.error(e);
        }
        return 0;
    }

    protected int delete(String sql, Object[] objectArr) {
        QueryRunner queryRunner = new QueryRunner(getDataSource());
        ArrayHandler arrayHandler = new ArrayHandler();

        try {
            int insert = queryRunner.update(sql, arrayHandler, objectArr);
            return insert;
        } catch (SQLException e) {
            logger.error(e);
        }
        return 0;
    }

    protected int update(String sql, Object[] objectArr) {
        QueryRunner queryRunner = new QueryRunner(getDataSource());
        ArrayHandler arrayHandler = new ArrayHandler();

        try {
            int insert = queryRunner.update(sql, arrayHandler, objectArr);
            return insert;
        } catch (SQLException e) {
            logger.error(e);
        }
        return 0;
    }

    protected  <T> List<T> queryForList(String sql, Object[] objectArr, Class<T> tClass) {
        QueryRunner queryRunner = new QueryRunner(getDataSource());
        try {
            List<T> mapList = (List<T>) queryRunner.query(sql, new BeanListHandler(tClass), objectArr);
            return mapList;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    protected  <T> T queryForObject(String sql, Object[] objectArr, Class<T> tClass) {
        QueryRunner queryRunner = new QueryRunner(getDataSource());
        try {
            T mapList = (T) queryRunner.query(sql, new BeanHandler(tClass), objectArr);
            return mapList;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}
